package com.tyk.bookstore.back.comment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tyk.bookstore.back.comment.model.entity.CommentDo;
import com.tyk.bookstore.back.comment.model.entity.ReplyDo;
import com.tyk.bookstore.back.comment.model.query.CommentPageQuery;
import com.tyk.bookstore.back.comment.model.result.CommentResultEnum;
import com.tyk.bookstore.back.comment.model.vo.CommentPageVo;
import com.tyk.bookstore.back.comment.model.vo.CommentVo;
import com.tyk.bookstore.back.comment.repository.CommentRepository;
import com.tyk.bookstore.back.comment.repository.ReplyRepository;
import com.tyk.bookstore.back.comment.service.CommentService;
import com.tyk.bookstore.back.comment.util.MapStructComment;
import com.tyk.bookstore.back.common.core.model.type.BinVo;
import com.tyk.bookstore.back.common.core.util.AssertUtil;
import com.tyk.bookstore.back.common.core.util.ObjUtil;
import com.tyk.bookstore.back.member.model.dto.Member4CommentDto;
import com.tyk.bookstore.back.member.service.MemberApiService;
import com.tyk.bookstore.back.order.service.OrderApiService;
import com.tyk.bookstore.back.product.model.dto.Book4CommentDto;
import com.tyk.bookstore.back.product.service.BookApiService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author tyk
 * @description 评论管理
 */
@Service
@RequiredArgsConstructor
public class CommentServiceImp implements CommentService {
    private final CommentRepository commentRepository;
    private final ReplyRepository replyRepository;
    private final BookApiService bookApiService;
    private final OrderApiService orderApiService;
    private final MemberApiService memberApiService;
    private final TransactionTemplate transactionTemplate;
    private final MapStructComment mapStructComment;

    @Override
    public CommentVo getById(Long id) {

        // 评论
        CommentDo comment = commentRepository.selectById(id);
        AssertUtil.notNull(comment, CommentResultEnum.COMMENT_NOT_FOUND);
        CommentVo vo = mapStructComment.toCommentVo(comment);

        // 会员昵称
        vo.setMemberName(
                memberApiService.getMemberNameById(comment.getMemberId())
        );

        // 回复
        List<ReplyDo> subList = replyRepository.selectListByCommentId(id);
        List<CommentVo.Reply> subVoList = mapStructComment.toCommentVo$CommentList(subList);
        Map<Long, String> idNameMap = memberApiService
                .getMember4CommentDtoListByIdList(
                        subList.stream().map(ReplyDo::getMemberId).toList()
                )
                .stream().collect(Collectors.toMap(
                        Member4CommentDto::getMemberId, Member4CommentDto::getNickname
                ));
        subVoList.forEach(sub -> {
            sub.setMemberName(idNameMap.get(sub.getMemberId()));
        });
        vo.setChildren(subVoList);

        return vo;
    }

    @Override
    public CommentPageVo getPage(CommentPageQuery query) {

        // 评论
        Page<CommentDo> page = new Page<>(query.getPage(), query.getLimit());
        LambdaQueryWrapper<CommentDo> w = buildBookPageQueryWrapper(query);
        commentRepository.selectPage(page, w);
        CommentPageVo pv = mapStructComment.toCommentPageVo(page);


        // 评论者名称
        HashSet<Long> memberIdSet = new HashSet<>(pv.getRecords().stream().map(CommentPageVo.Comment::getMemberId).toList());
        Map<Long, String> cnMap = memberApiService
                .getMemberNameListByIdSet(memberIdSet)
                .stream().collect(Collectors.toMap(BinVo::getId, BinVo::getValue));

        // 订单号
        Map<Long, String> onoMap = orderApiService.getOrderNoListByIdSet(
                pv.getRecords().stream().map(CommentPageVo.Comment::getOrderId).collect(Collectors.toSet())
        ).stream().collect(Collectors.toMap(BinVo::getId, BinVo::getValue));

        // 书籍信息
        Map<Long, Book4CommentDto> bdMap = bookApiService.getBook4CommentDtoListByIdSet(
                        pv.getRecords().stream().map(CommentPageVo.Comment::getBookId).collect(Collectors.toSet())
                ).stream()
                .collect(Collectors.toMap(Book4CommentDto::getId, it -> it));

        // 评论
        pv.getRecords().forEach(sub -> {
            Book4CommentDto bdt = bdMap.get(sub.getBookId());
            sub.setMemberName(cnMap.get(sub.getMemberId()))
                    .setOrderNo(onoMap.get(sub.getOrderId()));
            if (bdt == null) return;
            sub.setBookName(bdt.getName())
                    .setBookNo(bdt.getBookNo())
                    .setBookIsbn(bdt.getIsbn());
        });
        return pv;
    }


    @Override
    public void deleteById(Long id) {
        AssertUtil.isTrue(
                commentRepository.exist1Eq(
                        CommentDo::getId, id, CommentDo.class
                ),
                CommentResultEnum.COMMENT_NOT_FOUND
        );
        transactionTemplate.executeWithoutResult(status -> {
            commentRepository.deleteById(id);
            replyRepository.delete1Eq(
                    ReplyDo::getCommentId, id, ReplyDo.class
            );
        });
    }


    /**
     * 构建评论分页查询条件
     */
    private LambdaQueryWrapper<CommentDo> buildBookPageQueryWrapper(CommentPageQuery query) {

        LambdaQueryWrapper<CommentDo> w = new LambdaQueryWrapper<>();

        // 订单条件
        if (ObjUtil.notBlank(query.getOrderNo())) {
            Long orderId = orderApiService.getIdByOrderNo(query.getOrderNo());
            if (orderId != null)
                w.eq(CommentDo::getOrderId, orderId);
        }

        // 会员条件
        if (ObjUtil.notBlank(query.getNickname())) {
            List<Long> mis = memberApiService.getIdListByNicknameLike(query.getNickname());
            w.in(CommentDo::getMemberId, mis);
        }

        // 评论条件
        w.ge(query.getStarFrom() != null, CommentDo::getStar, query.getStarFrom());
        w.le(query.getStarTo() != null, CommentDo::getStar, query.getStarTo());

        w.ge(query.getCreateTimeFrom() != null, CommentDo::getCreateTime, query.getCreateTimeFrom());
        w.le(query.getCreateTimeTo() != null, CommentDo::getCreateTime, query.getCreateTimeTo());

        w.like(ObjUtil.notBlank(query.getKeyword()), CommentDo::getContent, query.getKeyword());

        w.orderBy(true, false, CommentDo::getCreateTime);

        return w;
    }

}
